iT邦幫忙

2026 iThome 鐵人賽

DAY 6
1
Claude AI

盡信 Claude,不如無 Code — 心法與全端實戰系列 第 6

Day 6 CLAUDE.md 日常維護:/doctor 幫你砍,/insights 幫你加

  • 分享至 

  • xImage
  •  

昨天那份 .md 之所以是唯一真相,是因為三種產出都從它長出來。今天這份 CLAUDE.md 不一樣,但它長出來的不是檔案,而是行為 —— 而且它只有一個讀者:那個讀者不是人。

怎麼寫 CLAUDE.md,網路上已經很多人寫過,官方文件也寫得很細,我先前也在 Medium 拆過 Apple 那份 91 行的 CLAUDE.md(見參考資料)。所以今天不教怎麼寫。今天講兩個內建指令:/doctor 讀你的檔案,告訴你哪些該砍;/insights 讀你的 session,告訴你哪些該加。 兩個我都實跑了,數字在下面。

在那之前,需要一分鐘的地圖 —— 不然看不懂它們在砍什麼、加什麼。


一分鐘版:CLAUDE.md 是什麼

第一,裡面每一句不是描述就是規定。 描述句像 Cloudflare 那份裡的 pnpm build — build the workspace(指令加一句它做什麼):AI 打開 package.json 就知道,你寫不寫都一樣。規定句像「不准把不可信輸入拼進 shell 指令」:沒有任何檔案能告訴它,因為那是一個決定。

第二,規定不保證被遵守。 官方文件寫得很直白:CLAUDE.md 對 Claude 是 context,不是強制設定。要「不管 AI 怎麼想都得擋住」,那是 lint、CI、hook 的事 —— 我把這種東西叫裁判。有裁判的規定是「擋」,沒裁判的是「請」。

第三,它不是一個檔案。 官方攤開來看,是四個層級加兩套系統,而且每一層進 context 的時機不同:

層級 位置 誰看得到
組織政策 /Library/Application Support/ClaudeCode/CLAUDE.md(macOS) 這台機器上每個人,個人設定蓋不掉
使用者 ~/.claude/CLAUDE.md 只有你,所有專案
專案 ./CLAUDE.md./.claude/CLAUDE.md 團隊,跟著版控走
本機 ./CLAUDE.local.md 只有你,這個專案(要進 .gitignore)

由上而下依序載入,離你啟動位置越近的,它越晚讀到。想知道實際載入了哪些:/context,看 Memory files 那一欄。

但更容易搞混的是:同一個檔案裡的規則,其實有四個家:

這條東西 該放哪 什麼時候進 context
每次都要遵守的規定 CLAUDE.md 每次
只在碰某類檔案時才適用的 .claude/rules/ + paths: 只有讀到符合的檔案時
給人看的理由、日期、踩過的坑 CLAUDE.md 裡的 <!-- --> 永遠不進(而且不花 token)
它自己從你的糾正裡學到的 auto memory(它自己寫) 每次(索引前 200 行)

中間兩格(paths: 和註解)跟直覺不一樣,我各驗了一次,證據留在這裡。

先驗註解。 官方文件說 block-level HTML 註解會在注入之前被剝掉。我分兩步驗。

第一步,它看不看得見。 同一個標記字串,只換位置:

標記放哪 問它「CLAUDE.md 裡有沒有這個字串」
<!-- ... --> 裡面 「沒有。」
註解外面,正常內文 「有。」

第二個是負對照。沒有這個對照,那句「沒有」可能只是它懶得看。

第二步,它花不花錢。 兩份 CLAUDE.md,規則內容一模一樣,差別只在其中一份帶了 600 行註解:

檔案大小 總輸入 token
56,916 bytes 20,769
16 bytes 20,769

一個 token 都不差。

要分清楚的是:這不是模型「看得懂註解,所以主動略過」—— 任何模型直接收到含註解的文字,照樣會算進 token。這是 Claude Code 在載入時就把它剝掉了,根本沒送出去。官方文件原文:

Block-level HTML comments in CLAUDE.md files are stripped before the content is injected into Claude's context. […] Comments inside code blocks are preserved. When you open a CLAUDE.md file directly with the Read tool, comments remain visible.

所以有三個邊界:只有自成一段的 block-level 註解會被剝掉;程式碼區塊裡的註解保留;它用 Read 自己去讀那個檔案時,註解也看得到。

⚠️ 算 token 的時候有個坑:cache_creationcache_read分配每次都不一樣,只看其中一個會以為有差。要看 input_tokens + cache_creation + cache_read總和才穩定。

再驗 paths: .claude/rules/ 底下的檔案可以帶一段 YAML frontmatter:

---
paths:
  - "src/api/**/*.ts"
---
# API 規則
- 所有 endpoint 都要輸入驗證

官方說它「只在 Claude 讀到符合的檔案時才載入」。我放了兩個暗號進去驗 —— 一條帶 paths,一條不帶:

探針 做了什麼 paths 那條 不帶的那條
1 不讀任何檔 沒有
2 先讀 src/a.ts(符合)
3 先讀 docs/note.md(不符合) 沒有

探針 2 還自己交代了原因:「讀取 src/a.ts 後,路徑範圍規則被載入」。

這一條解掉了一個矛盾。 官方建議 CLAUDE.md 200 行以內,理由是太長會吃 context 而且降低遵循率;但真實專案的規則只會越來越多。答案不是一味寫短,而是別讓它全部一直載入 —— 而這正是 /doctor 等一下要做的事。

順帶一提,CLAUDE.md 跟別的 agent 讀的 AGENTS.md 可以共用一份:@AGENTS.md 一行 import,或者乾脆 symlink。這兩種都有大廠在用 —— Cloudflare workers-sdkCLAUDE.md 全文 132 bytes,內容是 See @AGENTS.md;OpenAI openai-agents-pythonCLAUDE.md 是指向 AGENTS.md 的 symlink。

拿一份大廠的當範本

要看 /doctor 砍得準不準,得先有一份人手分類過的。我挑 Cloudflare workers-sdk(wranglerminiflare 的家;commit 71b6f10,2026-09-15)的 AGENTS.md,153 行,我逐句分類:

項數 內容
描述句 30 8 條指令、13 列目錄地圖、9 句「工具鏈長這樣」
規定句 36 有裁判 13、半個裁判 2、找不到 21

有裁判的 13 條全是能寫成明確判斷式的 —— 不准 any(no-explicit-any: error)、關 lint 要寫理由(自寫規則)、改依賴要更新 lockfile(CI --frozen-lockfile)。找不到的 21 條全是判斷型 —— 「註解要講 why」「先讀該套件的 AGENTS.md」「用 SDK 不要自己打 REST」。

它的第一段自己就寫著「copied versions, rule lists, and counts become stale」,而第 140 行就應驗了這句話:寫的是 .github/PULL_REQUEST_TEMPLATE.md,tree 裡實際是全小寫的 pull_request_template.md。GitHub 兩種都認,人沒感覺;一個 agent 在 Linux 上照這行 Read,會拿到 file not found。連寫得這麼好的一份,也會過期。 這就是為什麼要有工具定期替你看。

/doctor:讓它替你砍

官方定義它是一次「設定健檢」:查安裝有沒有重複或殘留、PATH、設定檔能不能解析;找沒在用的 skill、MCP server、plugin 各占多少 context;標出慢的 hook;查版本;然後是跟 CLAUDE.md 直接相關的三件事:**把本機的跟 checked-in 的去重;砍掉 checked-in 那份裡「Claude 從 codebase 就推得出來」的內容;把剩下每次都載入的指引搬進 skill 與巢狀 CLAUDE.md。**它先列發現、確認後才動手(修剪功能要 2.1.206 以上;別名 /checkup)。

對 Cloudflare 那份,它砍了什麼

我把 CLAUDE.mdAGENTS.mdpackage.json 放進一個空 repo,claude -p "/doctor"(2.1.271,343 秒、18 回合、$1.74)。它對 AGENTS.md 提了三刀,一刀都沒動,列完等我回 1、2、3

它提議 內容 對上我手工分的哪一類
4 條指令、目錄地圖 10 列、工具鏈那段,約 27 行 描述句 —— 幾乎重疊,它留了 3 列帶 gotcha 的
「不准 any」「type-only import」「註解要講 why」 有裁判的規定 —— 理由:那節自己說 pnpm check 是權威,這些跟 lint 重複。並註明「這個 checkout 沒有 lint 設定,我沒法核對,要留就說」
Cross-Tool 整節 → skill;Testing Conventions → .claude/rules/testing.mdpaths: ["**/*.test.*", …];PR 那節 → skill;「不要直接 commit main」留根檔 沒裁判的判斷型規定 —— 它判斷每次都要在 context 裡的只剩幾條

它估:每個 session 從 2.3k 降到 1.2k tokens。

三刀剛好對上前面三類,只有第二刀是我原本沒想到的:有裁判的規定它也砍。 想一下確實合理 —— 裁判在,規則寫在檔案裡只是重複 lint 會說的話;裁判不在,寫了也只是「請」。規則檔真正該留的,是「沒裁判、但每次都要遵守」的那幾條 —— 而那幾條最好還是按需載入。

對我這台機器,它砍了什麼

同一次跑它也掃了我的環境(它掃的是整台機器最近 50 個 session、14 個專案資料夾),跟 CLAUDE.md 無關但值得看:

  • 7 個裝了從沒用過的 skill,估 850 tokens,每個 session 都在 —— 它建議在 skillOverrides 一鍵關掉,可逆
  • 每個 session 固定進 context 的東西估 4.4k tokens(skill 清單 1.7k、AGENTS.md 2.3k、我的 ~/.claude/CLAUDE.md 0.4k、MCP 0 因為全部延遲載入);清完估 2.5k
  • 版本落後 2 個 patch;auto mode 已是預設;36 次權限拒絕全是寫入,沒有可以預先放行的唯讀指令

三件要知道的:

  1. 它估的是 token,不是行數。 「砍 27 行」值不值得看它省多少 context,而它給的是估值,/context 才是活的數字。
  2. 它會把有裁判的規定也砍掉 —— 前提是它看得到裁判。在那個空 repo 裡它看不到 lint 設定,所以它直接說「沒法核對」。在真實 repo 裡跑,不要拿節錄版來跑。
  3. 它不會替你判斷「這條規則還對不對」。 PR template 那行路徑錯了,它沒抓到 —— 那不是它的工作,那是 /insights 的方向。

/insights:讓它替你加

/doctor 讀檔案,/insights你過去的 session。它分析這台機器上最近的對話(一次最多分析 200 個沒看過的 session,太短的會跳過),產一份 HTML 報告到 ~/.claude/usage-data/report.html,八節:你在做什麼、你怎麼用、做得不錯的、哪裡出錯、還沒用的功能、新用法、更遠的、給團隊的回饋。跟 CLAUDE.md 直接相關的是「哪裡出錯」,和「還沒用的功能」底下那節 「Suggested CLAUDE.md Additions」:每條規則附上它從哪幾次摩擦推出來的理由,一鍵複製。

我跑了一次:69 個 session(178 個裡跳過太短的)、95 秒、$3.03。摩擦的分布長這樣:

摩擦類型 次數
寫出 bug 36
方向錯 17
環境問題 8
誤解需求 4
我拒絕了它的動作 4

然後給了 6 條建議加進 CLAUDE.md 的規則。其中一條是這樣的(其他五條含我的帳號與工作習慣,不放):

Verification Discipline —— 報數字之前,用第二種獨立的方法再驗一次;一次性腳本算出來的數字不要直接講。理由:好幾次 session 的計數事後才更正,含 XPCKeys 119 vs 82 那次。

那正是 Day 3 對賬表裡,我數錯的那一格(XPCKeys 的 case 數)。我沒告訴它,它從 session 紀錄裡自己撈出來的。

怎麼用它的建議

不要「Copy All」。 它的建議是模型讀你的 session 推出來的,同一個錯,它看到一次就可能想把它變成規則。六條我逐條問同一個問題:這條配得上裁判嗎?

  • 「報數字前用第二種方法再驗」—— 配不上裁判,是判斷型。留在 CLAUDE.md,它會是「請」。
  • 「commit 前檢查 git 身分」—— 配得上:一支 pre-commit hook 十行就擋住了。這種不要寫成句子,寫成 hook。
  • 「長任務要 nohup 背景跑」—— 配得上一半:可以留下原則,但真正的解法是換一種方式啟動 process。

也就是說,/insights 給你的只是候選,不是規則。它幫你做的是那件最難的事 —— 從 69 個 session 裡找出你一直在重複糾正的東西;配不配裁判、放哪一層、要不要按需載入,還是回到前面那張四個家的表。

代價與隱私: 一次大約 $3,用的是你的帳號額度;報告包含這台機器上所有專案的 session 摘要,別隨手分享。


總結

CLAUDE.md 怎麼寫,我今天其實只講三件事:每句不是描述就是規定;規定要配裁判,配不上的是「請」;它不是一個檔案,是四層兩系統。然後把修檔案這件事交出去:

  • /doctor 從檔案往下砍:砍描述句、砍有裁判的規定(裁判在就不用重複)、把判斷型規定搬去按需載入。在真實 repo 裡跑,它才看得到裁判。
  • /insights 從 session 往上加:從你一直在重複糾正的東西裡長出候選規則。逐條問配不配得上裁判,配得上的寫成 hook,不寫成句子。

砍與加之間留下的,才是 CLAUDE.md 真正該有的樣子:規定句、沒裁判、每次都要。

這一篇留下的心法:

CLAUDE.md 裡的每一句,不是描述就是規定。描述交給檔案系統;規定要有 lint、CI 或 hook 在背後擋 —— 沒有裁判的,AI 可能會跳過,而你不會知道。砍的事讓 /doctor 做,加的事讓 /insights 做;配不配得上裁判,自己判斷。


參考資料

  • Claude Code 官方文件 — /doctor/insightscode.claude.com/docs/en/commandscosts#analyze-your-usage-patterns(2026-09-16 查) —— 兩個實跑:/doctor 343 秒/18 回合/$1.74(空 repo 只放 Cloudflare 三個檔),/insights 69 個 session/95 秒/$3.03;Claude Code 2.1.271。/insights 報告含個人 session 內容,未公開

  • Claude Code 官方文件 — Memory / CLAUDE.mdcode.claude.com/docs/en/memory(2026-09-16 核對)—— 四個層級與載入順序、.claude/rules/paths:、auto memory、AGENTS.md 互通、200 行建議;HTML 註解剝除的原文在 How CLAUDE.md files load 那節

  • 官方 Hooks 文件(「要不管 Claude 怎麼想都得擋」時去這裡):code.claude.com/docs/en/hooks-guide

  • Cloudflare workers-sdk,commit 71b6f102f258e14e2b1dc23e9643cc74685d35cb(2026-09-15):github.com/cloudflare/workers-sdk—— CLAUDE.md(132 bytes)、AGENTS.md(153 行);裁判核對用到 .oxlintrc.jsoncpackages/lint-config-shared/rules/tools/deployments/validate-*.ts、CI 的 install action

  • OpenAI openai-agents-pythonCLAUDE.md 是指向 AGENTS.md 的 symlink(git tree mode 120000;2026-09-16 查):github.com/openai/openai-agents-python

  • 兩個實測的重現指令(Claude Code 2.1.271,2026-09-16 重跑;9/11 在 2.1.267 第一次跑,結論相同):

    mkdir -p t && cd t
    printf '# t\n- 規則一\n\n<!--\n標記 ZEBRA_NOTE_7741\n-->\n' > CLAUDE.md
    claude -p --output-format json "CLAUDE.md 裡有沒有 ZEBRA_NOTE_7741?不要用工具讀檔。"
    

    usage 欄位,比較 input_tokens + cache_creation + cache_read總和

  • 延伸閱讀:Apple 官方的 CLAUDE.md:91 行,零句廢話——那你的呢?—— 「怎麼寫」在那篇,這篇是「怎麼讓工具替你改」

  • awesome-claude-md —— Cloudflare 那份是從這裡的 Top Picks 挑的


上一篇
Day 5 一份 Markdown,三種產出,加上那些圖是怎麼來的
下一篇
Day 7 先寫規格,再讓 Plan Mode 把它補完整
系列文
盡信 Claude,不如無 Code — 心法與全端實戰8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言